<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SouleEngine文档</title>
    <style>
        :root {
            --bg-color: #0f0f17;
            --sidebar-bg: #1a1a2a;
            --text-color: #e0e0e0;
            --text-muted: #a0a0a0;
            --accent-color: #7a5af5;
            --code-bg: #1e1e2e;
            --border-color: #2a2a3a;
            --hover-bg: #2a2a3a;
        }
        
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
            background-color: var(--bg-color);
            color: var(--text-color);
            line-height: 1.6;
            display: flex;
            min-height: 100vh;
        }
        
        .sidebar {
            width: 280px;
            background-color: var(--sidebar-bg);
            height: 100vh;
            overflow-y: auto;
            position: sticky;
            top: 0;
            padding: 30px 0;
            border-right: 1px solid var(--border-color);
        }
        
        .sidebar-header {
            padding: 0 25px 20px;
            margin-bottom: 15px;
            border-bottom: 1px solid var(--border-color);
        }
        
        .sidebar-header h1 {
            font-size: 1.3rem;
            font-weight: 600;
            color: white;
            margin-bottom: 5px;
        }
        
        .sidebar-header p {
            font-size: 0.9rem;
            color: var(--text-muted);
        }
        
        .sidebar-nav {
            padding: 0 15px;
        }
        
        .sidebar-nav ul {
            list-style: none;
        }
        
        .sidebar-nav li {
            margin-bottom: 3px;
        }
        
        .sidebar-nav a {
            display: block;
            padding: 8px 12px;
            color: var(--text-color);
            text-decoration: none;
            border-radius: 6px;
            transition: all 0.2s ease;
            font-size: 0.95rem;
        }
        
        .sidebar-nav a:hover {
            background-color: var(--hover-bg);
            color: white;
        }
        
        .sidebar-nav a.active {
            background-color: var(--accent-color);
            color: white;
            font-weight: 500;
        }
        
        .sidebar-nav .section-title {
            color: var(--text-muted);
            font-size: 0.85rem;
            padding: 15px 12px 8px;
            margin-top: 10px;
            text-transform: uppercase;
            letter-spacing: 0.5px;
            font-weight: 600;
        }
        
        .main-content {
            flex: 1;
            padding: 40px 50px;
            max-width: 900px;
            margin: 0 auto;
        }
        
        h1, h2, h3, h4 {
            color: white;
            margin-bottom: 1.2rem;
            font-weight: 600;
        }
        
        h1 {
            font-size: 2.4rem;
            padding-bottom: 10px;
            border-bottom: 1px solid var(--border-color);
            margin-bottom: 2rem;
        }
        
        h2 {
            font-size: 1.8rem;
            margin-top: 3rem;
            padding-bottom: 0.5rem;
            border-bottom: 1px solid var(--border-color);
        }
        
        h3 {
            font-size: 1.4rem;
            margin-top: 2.5rem;
            border-bottom: 1px solid var(--border-color);
        }
        
        h4 {
            font-size: 1.1rem;
            margin-top: 2rem;
        }
        
        p {
            margin-bottom: 1.2rem;
            font-size: 1.05rem;
            line-height: 1.7;
        }
        
        a {
            color: var(--accent-color);
            text-decoration: none;
            font-weight: 500;
        }
        
        a:hover {
            text-decoration: underline;
        }
        
        pre {
            background-color: var(--code-bg);
            padding: 16px;
            border-radius: 8px;
            overflow-x: auto;
            margin: 1.5rem 0;
            border: 1px solid var(--border-color);
            font-size: 0.95rem;
            line-height: 1.5;
        }
        
        code {
            font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
            color: #e0e0e0;
        }
        
        p code, li code {
            background-color: var(--code-bg);
            padding: 0.2em 0.4em;
            border-radius: 4px;
            font-size: 0.9em;
            border: 1px solid var(--border-color);
        }
        
        ul, ol {
            margin-bottom: 1.5rem;
            padding-left: 1.8rem;
        }
        
        li {
            margin-bottom: 0.5rem;
            line-height: 1.6;
        }
        
        table {
            width: 100%;
            border-collapse: collapse;
            margin: 1.5rem 0;
            border: 1px solid var(--border-color);
            border-radius: 8px;
            overflow: hidden;
        }
        
        th, td {
            padding: 12px 16px;
            text-align: left;
            border-bottom: 1px solid var(--border-color);
        }
        
        th {
            background-color: var(--sidebar-bg);
            color: white;
            font-weight: 600;
        }
        
        tr:hover {
            background-color: var(--hover-bg);
        }

        .pop {
            color: #27ae60;
            font-weight: bold;
        }
        .oop {
            color: #e74c3c;
            font-weight: bold;
        }
        
        @media (max-width: 1024px) {
            .sidebar {
                width: 240px;
            }
            
            .main-content {
                padding: 30px;
            }
        }
        
        @media (max-width: 768px) {
            body {
                flex-direction: column;
            }
            
            .sidebar {
                width: 100%;
                height: auto;
                position: relative;
                border-right: none;
                border-bottom: 1px solid var(--border-color);
                padding: 20px 0;
            }
            
            .main-content {
                padding: 25px;
            }
        }
    </style>
  
    <link rel="stylesheet" href="../css/newpvsc.css" />
    <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-core.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
</head>
<body>
    <!-- 侧边栏导航 -->
    <div class="sidebar">
        <div class="sidebar-header">
            <h1>SoulEngine文档</h1>
            <p>FOR SoulEngine v2.3.4</p>
        </div>
        <nav class="sidebar-nav">
            <ul>
                <li class="section-title">入门指南</li>
                <li><a href="../index.html">注意事项</a></li>
                <li><a href="../pages/s1-download.html">下载与配置</a></li>
            </ul>
            <ul>
                <li class="section-title">基础开发</li>
                <li><a href="../pages/s2-basics.html">基础入门</a></li>
                <li><a href="../pages/s2-sprites.html">贴图与弹幕</a></li>
                <li><a href="../pages/s2-typer.html">文本与打字机</a></li>
                <li><a href="../pages/s2-collisions.html">碰撞</a></li>
                <li><a href="../pages/s2-player.html">玩家</a></li>
                <li><a href="../pages/s2-camera.html">摄像机</a></li>
                <li><a href="../pages/s2-easings.html">缓动</a></li>
                <li><a href="../pages/s2-shaders.html">着色器</a></li>
                <li><a href="../pages/s2-audio.html">音频</a></li>
                <li><a href="../pages/s2-globals.html">全局变量</a></li>
                <li><a href="../pages/s2-keyboard.html">按键检测</a></li>
                <li><a href="../pages/s2-window.html">游戏窗口</a></li>
            </ul>
            <ul>
                <li class="section-title">进阶开发</li>
                <li><a href="../pages/s3-gamejolt.html">Gamejolt API</a></li>
                <li><a href="../pages/s3-json.html">JSON</a></li>
            </ul>
            <ul>
                <li class="section-title">遭遇战斗</li>
                <li><a href="../pages/s4-scenes.html">场景介绍</a></li>
                <li><a href="../pages/s4-battle.html">战斗场景</a></li>
            </ul>
            <ul>
                <li class="section-title">其余页面</li>
                <li><a href="../pages/se-keyslist.html">键盘表</a></li>
                <li><a href="../pages/lua-tutorial.html">Lua教程</a></li>
            </ul>
        </nav>
    </div>
    
    <!-- 主内容区域 -->
    <div class="main-content">
        <h1>贴图</h1>
        <p>
            您是否曾想过：游戏中的图片是怎么生成的？<br>
            那么现在，在SoulEngine的文档中，<strong>你来对地方了</strong>。
        </p>
        <h2>贴图的创建</h2>
        <p>
            我们只需要使用一个……类似于Create Your Frisk中贴图的创建方法的一个函数。
        </p>
        <pre>
            <code class="language-lua">
                -- 创建一个图层为1、名称为bullet.png的贴图
                local bullet = sprites.CreateSprite("bullet.png", 1)
            </code>
        </pre>
        是不是很简单？
        如果你这么做了，你就会看到一个bullet.png图片出现在了屏幕<strong>(320, 240)</strong>的位置上。<br>
        <strong>（很明显因为你没给位置，所以这个函数会默认给你一个位置）</strong><br>
        <p>
            接下来，我们直观地感受一下关于这个贴图的图层顺序。<br>
            创建一个新的poseur.png，给予它另一个名字，图层比之前的要高一个。
        </p>
        <pre>
            <code class="language-lua">
                -- 创建一个图层为2、名称为poseur.png的贴图
                local poseur = sprites.CreateSprite("poseur.png", 2)
            </code>
        </pre>
        于是你就会神奇的发现，原先创建的bullet.png不见了。<br>
        当然，是poseur盖住了原先的bullet。<br>
        <strong>接下来请自己试试重新修改bullet.png的图层。使其高于poseur。</strong>
        <h2>贴图的属性</h2>
        <p>
            当然，贴图是<strong>不能</strong>只是单纯的一个图片。<br>
            我们可能需要修改它的一些属性来达成想要的效果。<br>
            比如：改变它的角度、改变它的大小、改变它的颜色……<br><br>
            <strong>接下来，我们来尝试一下。</strong>
            <pre>
                <code class="language-lua">
                    -- 创建一个图层为1、名称为bullet.png的贴图
                    local bullet = sprites.CreateSprite("bullet.png", 1)

                    -- 设置bullet的旋转角度为45度.
                    bullet.rotation = 45

                    -- 设置bullet的长为原来的2倍、宽为原来的0.5倍.
                    bullet:Scale(2, 0.5)

                    -- 设置bullet的颜色为红色.
                    bullet.color = {1, 0, 0}

                    -- ...
                </code>
            </pre>
        </p>
        <p>
            我将列举出贴图所有属性的值和方法。<br>
        </p>
        <h3>贴图的属性</h3>
        <p>
            <code class="language-lua">sprite.path</code><br>
            <code>类型：字符串(string)</code><br>
            贴图的路径，例如 "bullet.png"。
        </p>
        <p>
            <code class="language-lua">sprite.realName</code><br>
            <code>类型：字符串(string)</code><br>
            去掉扩展名后的贴图名称。
        </p>
        <p>
            <code class="language-lua">sprite.image</code><br>
            <code>类型：Image</code><br>
            Love2D 加载的图像对象。
        </p>
        <p>
            <code class="language-lua">sprite.layer</code><br>
            <code>类型：字符串/数值</code><br>
            当前贴图所在的图层。（数值越大图层越高）
        </p>
        <p>
            <code class="language-lua">sprite.x, sprite.y</code><br>
            <code>类型：数值(number)</code><br>
            贴图的坐标。
        </p>
        <p>
            <code class="language-lua">sprite.width, sprite.height</code><br>
            <code>类型：数值(number)</code><br>
            贴图宽度与高度，自动从图像获取。
        </p>
        <p>
            <code class="language-lua">sprite.xpivot, sprite.ypivot</code><br>
            <code>类型：数值(number)</code><br>
            锚点位置（范围通常为0-1）。
        </p>
        <p>
            <code class="language-lua">sprite.rotation</code><br>
            <code>类型：数值(number)</code><br>
            贴图的旋转角度（单位：度）。
        </p>
        <p>
            <code class="language-lua">sprite.velocity</code><br>
            <code>类型：表(table)</code><br>
            包含 <code>x</code> 和 <code>y</code> 速度分量的表。
        </p>
        <p>
            <code class="language-lua">sprite.xscale, sprite.yscale</code><br>
            <code>类型：数值(number)</code><br>
            贴图的缩放比例。
        </p>
        <p>
            <code class="language-lua">sprite.xshear, sprite.yshear</code><br>
            <code>类型：数值(number)</code><br>
            贴图的剪切量。
        </p>
        <p>
            <code class="language-lua">sprite.alpha</code><br>
            <code>类型：数值(0-1)</code><br>
            透明度。
        </p>
        <p>
            <code class="language-lua">sprite.color</code><br>
            <code>类型：表(table)</code><br>
            颜色表，格式为 {r, g, b, a}。
        </p>
        <p>
            <code class="language-lua">sprite.visible</code><br>
            <code>类型：布尔(boolean)</code><br>
            是否可见。
        </p>
        <p>
            <code class="language-lua">sprite.isactive</code><br>
            <code>类型：布尔(boolean)</code><br>
            是否处于激活状态。
        </p>

        <h3>动画属性</h3>
        <p>
            <code class="language-lua">sprite.animation</code><br>
            <code>类型：表(table)</code><br>
            包含动画帧序列、间隔、模式等。
        </p>

        <h3>特殊效果</h3>
        <p>
            <code class="language-lua">sprite.shaders</code> / <code>sprite.stencils</code><br>
            <code>类型：表(table)</code><br>
            着色器和模板缓冲相关配置。
        </p>
        <p>
            <code class="language-lua">sprite.dust</code><br>
            <code>类型：表(table)</code><br>
            用于“尘埃化”特效，包含贴图像素点的行信息。
        </p>

        <h3>贴图的函数</h3>
        <ul>
            <li><code class="language-lua">sprite:MoveTo(x, y)</code>：设置贴图到指定位置。</li>
            <li><code class="language-lua">sprite:Move(dx, dy)</code>：相对移动。</li>
            <li><code class="language-lua">sprite:SetSpeed(x, y)</code>：设置移动速度。</li>
            <li><code class="language-lua">sprite:Scale(x, y)</code>：设置缩放。</li>
            <li><code class="language-lua">sprite:Pivot(x, y)</code>：设置旋转锚点。</li>
            <li><code class="language-lua">sprite:Shear(x, y)</code>：设置剪切。</li>
            <li><code class="language-lua">sprite:Set(path)</code>：更换贴图图像。</li>
            <li><code class="language-lua">sprite:GetPosition()</code>：返回当前坐标。</li>
            <li><code class="language-lua">sprite:SetAnimation(frames, interval, mode)</code>：设置动画帧、间隔和模式（loop、oneshot、oneshot-empty）。</li>
            <li><code class="language-lua">sprite:SetStencils(stencils)</code>：设置模板缓冲（遮罩）。</li>
            <li><code class="language-lua">sprite:SetShaders(shaders)</code>：设置着色器。</li>
            <li><code class="language-lua">sprite:Dust(sound, destroy)</code>：触发尘化特效并销毁。</li>
            <li><code class="language-lua">sprite:Destroy()</code>：彻底销毁贴图。</li>
            <li><code class="language-lua">sprite:Remove()</code>：移除贴图（与Destroy功能相同）。</li>
        </ul>

        <h3>全局函数</h3>
        <ul>
            <li><code class="language-lua">sprites.CreateSprite(path, layer, filters)</code>：创建一个新的贴图对象。</li>
            <li><code class="language-lua">sprites.Update()</code>：更新所有贴图状态。</li>
            <li><code class="language-lua">sprites.Draw()</code>：绘制所有贴图。</li>
            <li><code class="language-lua">sprites.clear()</code>：清除所有贴图。</li>
        </ul>

        <h2>转换弹幕</h2>
        只是有了贴图，那可不够，这些贴图中有一部分是需要转化为弹幕对玩家造成实质性的伤害的。<br>
        对于SoulEngine，我们使用<code class="language-lua">sprite.isBullet = true</code>来将其强制转化为弹幕类型。<br>
        示例：<br>
        <pre>
            <code class="language-lua">
                local sprite = sprites.CreateSprite("bullet.png", 1)
                sprite.isBullet = true
            </code>
        </pre>
        那么这时候，这个贴图将被强制转化为<strong>弹幕</strong>类型，执行对玩家造成伤害的逻辑。<br>
        如果要给贴图分属性，例如普通攻击、蓝色攻击、橙色攻击等……在SoulEngine中，我们使用<code class="language-lua">sprite['HurtMode'] = "xxx"</code>的格式来进行属性设置。<br>
        示例：<br>
        <pre>
            <code class="language-lua">
                local sprite = sprites.CreateSprite("bullet.png", 1)
                sprite.isBullet = true
                sprite['HurtMode'] = "orange"
            </code>
        </pre>
        该弹幕将变为橙色属性的弹幕。

        <h2>一些示例</h2>
        让贴图化成尘埃：
        <pre>
            <code class="language-lua">
                local sprite = sprites.CreateSprite("bullet.png", 1)
                sprite:Dust(true, true)
            </code>
        </pre>
        <br><br>
        创建一个有抗锯齿的贴图：
        <pre>
            <code class="language-lua">
                local sprite = sprites.CreateSprite("bullet.png", 1, {"linear", "linear"})
            </code>
        </pre>
        <br><br>
        创建一个带Shader的贴图（这里举渐变色效果为例）：
        <pre>
            <code class="language-lua">
                -- 创建渐变Shader对象并设置颜色
                local shader = love.graphics.newShader("Scripts/Shaders/gradient")
                shader:send("color_tl", {1, 0, 0, 1})
                shader:send("color_tr", {0, 0, 1, 1})
                shader:send("color_br", {0, 1, 0, 1})
                shader:send("color_bl", {1, 1, 0, 1})

                -- 创建贴图并设置Shader
                local bul = sprites.CreateSprite("poseur.png", 1)
                bul:SetShaders({shader})
            </code>
        </pre>
        <br><br>
        创建一个带有多个贴图动画的贴图：
        <pre>
            <code class="language-lua">
                -- 创建贴图并设置动画
                local bul = sprites.CreateSprite("bullet.png", 1)

                -- 这将每10帧切换一次，且循环播放。
                bul:SetAnimation({"bullet.png", "poseur.png"}, 10, "loop")

                -- 这将每5帧切换一次，且仅播放一次。
                bul:SetAnimation({"bullet.png", "poseur.png"}, 5, "oneshot")

                -- 这将每5帧切换一次，且仅播放一次，当动画播放完毕后，会清空贴图。
                bul:SetAnimation({"bullet.png", "poseur.png"}, 5, "oneshot-empty")
            </code>
        </pre>
    </div>
</body>
</html>